﻿//----------------------------------------------------------------
//CodeArt.
//
//文件描述:
//
//创 建 人: dreamnan@hotmail.com(Blog:http://www.cnblogs.com/dreamnan)
//创建日期: 2010-6-15
//
//修订记录: 
// 2011-1209 SelectedFields改成保存InternalName
//          默认查询当前视图的字段    
//          最后一行不满时，按钮不放到新行中  
//          修改样式，满足正常moss显示。
//          可以从列表的所有字段中选择要查询的字段
//          资源文件放到12/Resources中,默认资源文件改成英文。     
//          基类改成BaseSPWebPart，可能造成跟以前wp不兼容，需要删除旧wp，重新添加
//----------------------------------------------------------------

using System;
using System.Collections.Generic;

using System.ComponentModel;
using System.Reflection;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;
using System.Configuration;
using System.IO;
using System.Data;
using System.Text;

namespace CodeArt.SharePoint.SmartQuery
{
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.SharePoint.WebPartPages;

    using CodeArt.SharePoint.CamlQuery;
    using CodeArt.SharePoint.SmartQuery;
using System.Web.UI.WebControls.WebParts;
    using Microsoft.SharePoint.Administration;

    [DefaultProperty("Text"), ToolboxData("<{0}:ListQueryWebPart runat=server></{0}:ListQueryWebPart>"), XmlRoot(Namespace = "CodeArt.SharePoint.SmartQuery")]
    public class ListQueryWebPart : BaseSPWebPart, ICamlProvider
    {
        #region Variable

        //private string defaultTitle;
        private bool redrawingSuspended;
        private int columnsNum = 4;
        private string _selectedFields;

        [NonSerialized]
        private Table tbSimpleSearch = new Table();
        //private Table tbComplexSearch = new Table();
        [NonSerialized]
        private Table tbButtonSearch = new Table();
        [NonSerialized]
        private Button btnSearches = new Button();
        //private Coolite.Ext.Web.ScriptManager sm = new Coolite.Ext.Web.ScriptManager();

        internal static char Separator =  ';';

        internal static List<string> ExcludedFields =
            new List<string> { "DocIcon", "LinkTitle", "LinkTitle2", "LinkTitleNoMenu", "LinkFilenameNoMenu", "LinkFilename", "LinkFilename2",
            "ItemChildCount","FolderChildCount", "Edit"};

        #endregion

        #region construct

        /// <summary> 
        /// 构造函数
        /// </summary>
        public ListQueryWebPart()
        {
            //base.Init += new EventHandler(this.SearchesList_Init);
        }

        #endregion

        #region Properties

        //public new SPSite Site
        //{
        //    get { return this.ItemContext.Site; }
        //}

        protected SPWeb Web
        {
            get { return SPContext.Current.Web; }
        }

        private SPList _list;
        protected internal virtual SPList List
        {
            get 
            {
                if (_list == null)
                {
                    _list = SPContext.Current.List;
                    if (_list == null)
                    {
                        throw new Exception("can't find current list");
                    }
                }
                return _list;
            }
        }       
        
        /// <summary>
        /// 最多显示条目
        /// </summary>
        [Personalizable(PersonalizationScope.Shared)]
        //FriendlyName("显示列数"),
        //Description("输入查询面板的列数，默认为4列。"),
        [WebBrowsable(false),DefaultValue(4)]
        public int ColumnsNum
        {
            get
            {
                return this.columnsNum;
            }
            set
            {
                this.columnsNum = value;
            }
        }

        private bool exportEnabled;
        [WebBrowsable(true),DefaultValue(false)]
        [Personalizable(PersonalizationScope.Shared)]
        public bool ExportEnabled
        {
            get
            {
                return this.exportEnabled;
            }
            set
            {
                this.exportEnabled = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        [FriendlyName("查询Field的InternalName字符串"),
        Description("格式为Title;Create;Modified"),
        DefaultValue("")]
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(false)]
        public string SelectedFields
        {
            get
            {
                return this._selectedFields;
            }
            set
            {
                this._selectedFields = value;
            }
        }

        #endregion

        internal const string PostQueryJS = @"function SmartQuery_PostQuery() {
         _spSuppressFormOnSubmitWrapper = true;
        var url = window.location.href;
        if (url.indexOf('?') == -1 || url.indexOf('Paged=TRUE&') == -1)
            return;

        var arr = url.split('?');
        var postUrl = arr[0] + '?';
        var arrQueryStr = arr[1].split('&');
        for (var i = 0; i < arrQueryStr.length; i++) {
            var q = arrQueryStr[i];
            if (q == '') continue;
            var key = q.split('=')[0];
            if (key == 'Paged' || key == 'PagedPrev' || key == 'p_ID' || key == 'PageFirstRow') {
                continue;
            } else {
                postUrl = postUrl + q + '&';
            }
        }
        SubmitFormPost(postUrl);
    }";

        protected internal virtual bool IsFieldQueryEnabled(string field)
        {
            return !ExcludedFields.Contains(field);
        }

        protected virtual string GetDefaultSelectedFields()
        {
            List<string> fieldList = new List<string>();
            var list = this.List;
            if (SPContext.Current.ViewContext != null && SPContext.Current.ViewContext.View != null)
            {
                var fields = SPContext.Current.ViewContext.View.ViewFields.ToStringCollection();
                foreach (string f in fields)
                {
                    if (f == "LinkTitle" || f == "LinkTitleNoMenu" || f == "Title")
                    {
                        if (!fieldList.Contains("Title"))
                            fieldList.Add("Title");
                    }
                    else if (f == "LinkFilename")
                    {
                        if (!fieldList.Contains("FileLeafRef"))
                            fieldList.Add("FileLeafRef");
                    }
                    else if (f == "Attachments")
                    {
                        continue;
                    }
                    else if (IsFieldQueryEnabled(f))
                    {                     
                        if(!fieldList.Contains(f))
                         fieldList.Add(f);
                    }
                }
            }
            return String.Join(";", fieldList.ToArray());
        } 

        #region Override Method

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            Page.ClientScript.RegisterClientScriptBlock(typeof(ListQueryWebPart), "SmartQuery_PostQuery",
                PostQueryJS, true);
        }

        ///// <summary>
        ///// 创建子控件
        ///// </summary>
        protected override void CreateChildControls()
        {
            if (this.ChildControlsCreated) return;

            this.Controls.Clear();
            //Coolite.Ext.Web.ScriptManager sm = new Coolite.Ext.Web.ScriptManager();
            //this.Controls.Add(sm);
            try
            {
                //base.UseDefaultStyles = false;

                if (String.IsNullOrEmpty(this.SelectedFields))
                    this.SelectedFields = GetDefaultSelectedFields();
              
                if (!string.IsNullOrEmpty(this.SelectedFields))
                {
                    this.Controls.Add(this.tbSimpleSearch);
                    tbSimpleSearch.ID = "tbSimpleSearch";
                    //tbSimpleSearch.Attributes["runat"] = "server";
                    tbSimpleSearch.Attributes.Add("class", "ms-formtable");//ms-formtable");
                    
                    //tbSimpleSearch.Attributes.Add("width", "100%");
                    
                    tbSimpleSearch.Attributes.Add("cellpadding", "2");
                    tbSimpleSearch.Attributes.Add("cellspacing", "2");
                    tbSimpleSearch.Attributes.Add("border", "0");
                    //tbSimpleSearch.Attributes.Add("style", "padding-left:10px;padding-top:10px");
                    this.Controls.Add(this.tbSimpleSearch);

                    tbSimpleSearch.Controls.Clear();

                    string[] fields = this.SelectedFields.Split(Separator);
                    TableRow fieldSimpleTr = new TableRow();
                    int colIndex = 0;
                    foreach (string field in fields)
                    {
                        fieldSimpleTr.Controls.Add(CreateLabelCell(field));
                        fieldSimpleTr.Controls.Add(CreateFieldCell(field));
                        colIndex ++;

                        if (colIndex == this.ColumnsNum)
                        {
                            colIndex = 0;
                            this.tbSimpleSearch.Rows.Add(fieldSimpleTr);
                            
                            //TableRow row1 = new TableRow();
                            //TableCell cell1 = new TableCell();
                            //cell1.Attributes.Add("colspan", Convert.ToString(this.ColumnsNum*2));
                            //cell1.Controls.Add(new ToolPartItemSeparator());
                            //row1.Cells.Add(cell1);
                            //this.tbSimpleSearch.Controls.Add(row1);
                            
                            fieldSimpleTr = new TableRow();
                        }
                    }
                    this.tbSimpleSearch.Rows.Add(fieldSimpleTr);

                    var maxColCount = this.ColumnsNum * 2;
                    var btnCell = CreateSearchButton();
                    if (fieldSimpleTr.Cells.Count < maxColCount) //by zjy, 2011-12, 充分利用最后一行
                    {
                        var span = maxColCount - fieldSimpleTr.Cells.Count;
                        for (int i = 1; i < span; i++)
                        {
                            fieldSimpleTr.Cells.Add(new TableCell());
                        }
                        btnCell.ColumnSpan = 1;
                        btnCell.HorizontalAlign = System.Web.UI.WebControls.HorizontalAlign.Left;
                        fieldSimpleTr.Cells.Add(btnCell);
                    }
                    else
                    {
                        TableRow buttonRow = new TableRow();
                        buttonRow.Controls.Add(btnCell);
                        this.tbSimpleSearch.Rows.Add(buttonRow);
                    }                  
                }
                // this.btnSearches.Click += new EventHandler(btnSearches_Click);               
                this.ChildControlsCreated = true;

                //保证2010下，控件能显示出边框
                if(SPFarm.Local.BuildVersion.Major>12)
                    CssRegistration.Register("forms.css"); //add by zjy , 2007下会出错

            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            this.EnsureChildControls();
        }
            
        #region ICamlProvider 成员

        [NonSerialized]
        private CamlExpression _Expression;
        public virtual CamlExpression QueryExpression
        {
            get
            {
                if (_Expression != null)
                    return _Expression;

                var queryCtls = this.GetQueryControls();
                foreach (var ctl in queryCtls)
                {
                    CamlExpression tempExpr = ctl.QueryExpression;

                    if (tempExpr != null)
                    {
                        if (_Expression == null)
                            _Expression = tempExpr;
                        else
                            _Expression = _Expression && tempExpr;
                    }
                }
                return _Expression;

                //foreach (TableRow row in tbSimpleSearch.Rows)
                //{
                //    foreach (TableCell cell in row.Cells)
                //    {
                //        if (cell.Controls.Count == 0)
                //            continue;
                //        Control ctl = cell.Controls[0];
                //        if (ctl is ICamlProvider)
                //        {
                //            ICamlProvider p = (ICamlProvider)ctl;

                //            CamlExpression tempExpr = p.QueryExpression;

                //            if (tempExpr != null)
                //            {
                //                if (_Expression == null)
                //                    _Expression = p.QueryExpression;
                //                else
                //                    _Expression = _Expression && p.QueryExpression;
                //            }
                //        }
                //    }
                //}
                //return _Expression;
            }
        }

        private List<IQueryControl> _queryControls = new List<IQueryControl>();
        protected void RegisterQueryControl(IQueryControl ctl)
        {
            if(!_queryControls.Contains(ctl))
                _queryControls.Add(ctl);
        }

        public virtual IList<IQueryControl> GetQueryControls()
        {
            this.EnsureChildControls();
            return _queryControls;

           //IList<IQueryControl> ctls = new List<IQueryControl>();

           // foreach (TableRow row in tbSimpleSearch.Rows)
           // {
           //     foreach (TableCell cell in row.Cells)
           //     {
           //         if (cell.Controls.Count == 0)
           //             continue;
           //         Control ctl = cell.Controls[0];
           //         if (ctl is IQueryControl)
           //         {
           //             ctls.Add((IQueryControl)ctl);
           //         }
           //     }
           // }
           // return ctls; 
        }

        #endregion

        public override EditorPartCollection CreateEditorParts()
        {
            var editors = base.CreateEditorParts();

            EditorPart[] newEditors = new EditorPart[1];
            newEditors[0] = new ListQueryToolPart(this);
            newEditors[0].ID = "ListQueryToolPart";

            return new EditorPartCollection(editors, newEditors);
        }
                 
        #endregion

        /// <summary>
        /// 延缓重画
        /// </summary>
        internal void SuspendRedraw()
        {
            this.redrawingSuspended = true;
        }

        /// <summary>
        /// 重启重画
        /// </summary>
        internal void ResumeRedraw()
        {
            this.redrawingSuspended = false;
            this.DoRedraw();
        }

        internal void DoRedraw()
        {
            if (!this.redrawingSuspended)
            {
                base.ChildControlsCreated = false;
                this.EnsureChildControls();
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            try
            {
                ApplyQueryOnLoad();
            }
            catch (Exception ex)
            {                
                this.RegisterError(ex);
            }
        }

        protected bool IsQueryButtonClicked
        {
            get
            {
                if (Page.IsPostBack)
                {
                    return Page.Request.Form[this.btnSearches.UniqueID] != null;
                }
                else
                {
                    return false;
                }
            }
        }

        protected virtual void ApplyQueryOnLoad()
        {
            if (!Page.IsPostBack)
                return;

            if (this.QueryExpression == null)
                return;

            string qxml = CamlBuilder.Where(this.List, this.QueryExpression);
            this.SetCurrentListViewSchemaQuery(qxml);
        }

        #region private method
        protected CamlExpression AppendExpression(CamlExpression expr1, CamlExpression expr2)
        {
            if (expr1 == null)
                return expr2;
            else if (expr2 == null)
                return expr1;
            else
                return expr1 && expr2;
        }

        /// <summary>
        /// 改变当前列表的查询过滤条件
        /// </summary>
        /// <param name="qxml"></param>
        protected virtual void SetCurrentListViewSchemaQuery(string qxml)
        {
            if (String.IsNullOrEmpty(qxml)) return;

            if (this.Zone == null)
                throw new Exception("ListQueryWebPart must be added to a WebPartZone");

            ListWebPartQueryManager.ChangeWebPartsQuery(this.List, this.Zone.WebParts, qxml, this.IsQueryButtonClicked);       
        }

        protected virtual string GetFieldLabel(string field)
        {
            var f = this.List.Fields.GetField(field);
            return f.Title;
        }
          
        private TableCell CreateLabelCell(string field)
        {
            var f = GetFieldLabel(field);

            TableCell tcTemp = new TableCell();
            tcTemp.VerticalAlign = VerticalAlign.Middle;
            tcTemp.HorizontalAlign = HorizontalAlign.Left;
            //int intPercentage = 100 / this.ColumnsNum;
            //tcTemp.Attributes.Add("style", "width: " + intPercentage.ToString() + "%; ");
            //tcTemp.Attributes.Add("class", "ms-formlabel");
            tcTemp.Wrap = false;
            tcTemp.Controls.Add(new LiteralControl( " &nbsp; " + f + "&nbsp;"));

            return tcTemp;
        }

        private TableCell CreateFieldCell(string field)
        {
            TableCell tcTemp = new TableCell();
            tcTemp.VerticalAlign = VerticalAlign.Middle;
            tcTemp.HorizontalAlign = HorizontalAlign.Left;
           // int intPercentage = 80 / this.ColumnsNum;
           // tcTemp.Attributes.Add("style", "width: " + intPercentage.ToString() + "%; ");
            //tcTemp.Attributes.Add("class", "ms-formbody");
            tcTemp.Attributes.Add("nowrap","true");

            //QueryControl ctlField = CreateQueryControl();
            //ctlField.ID = "ft_" + field;
            //ctlField.FieldName = field;
            //ctlField.ShowTitle = false;
            //ctlField.Attributes.Add("style", "width:90%");
 
            var ctlField = CreateQueryControl(field);
            this.RegisterQueryControl(ctlField);
            tcTemp.Controls.Add((Control)ctlField);  

            return tcTemp;
        }

        [NonSerialized]
        private QueryControlFactory ctlFactory;

        protected virtual QueryControlFactory ControlFactory
        {
            get
            {
                if (this.ctlFactory == null)
                    this.ctlFactory = new QueryControlFactory();
                return this.ctlFactory;
            }
        }

        protected virtual IQueryControl CreateQueryControl(string field)
        {
            QueryControl ctlField = new QueryControl();
            ctlField.ControlFactory = this.ControlFactory;
            ctlField.ID = "ft_" + field;
            ctlField.FieldName = field;
            ctlField.ShowTitle = false;
            //this.RegisterQueryControl(ctlField);
            return ctlField;
        }

        private TableCell CreateSearchButton()
        {
            TableCell tcTemp = new TableCell();
            tcTemp.VerticalAlign = VerticalAlign.Bottom;
            tcTemp.HorizontalAlign = HorizontalAlign.Right;
            tcTemp.ColumnSpan = this.ColumnsNum*2;
            //tcTemp.Attributes.Add("style", "width:99%");
            this.btnSearches.ID = "btnSearches";
            //this.btnSearches.Attributes.Add("class", "ms-ButtonHeightWidth");
            this.btnSearches.Text = " "+ResourcesHelper.GetResourceString("Search", "查询") + " ";
            this.btnSearches.OnClientClick = "SmartQuery_PostQuery()";
            tcTemp.Controls.Add(this.btnSearches);
            this.btnSearches.Click += new EventHandler(btnSearches_Click);

            if (this.ExportEnabled)
            {
                Button btnExport = new Button();
                btnExport.ID = "btnExport";
                btnExport.Text = " " + ResourcesHelper.GetResourceString("Export", "导出") + " ";
                btnExport.Click += new EventHandler(btnExport_Click);
                tcTemp.Controls.Add(btnExport);
            }

            return tcTemp;
        }

        void btnExport_Click(object sender, EventArgs e)
        {
            ApplyExport();
        }

        protected virtual void ApplyExport()
        {
            if (this.Zone == null)
                throw new Exception("ListQueryWebpart must be added to a WebPartZone");

            var where = CamlBuilder.Where(this.QueryExpression);

            var queryView = ListWebPartQueryManager.GetQueryView(this.List, this.Zone.WebParts);
            if (queryView != null)
            {
                where = ListWebPartQueryManager.MergeViewQuery(queryView, where);               
            }

            SPQuery spQuery = queryView == null ? new SPQuery() : new SPQuery(queryView);
            spQuery.Query = where;
           
            if (queryView != null)
            {
                spQuery.ViewFields = queryView.ViewFields.SchemaXml;
                spQuery.ViewAttributes = "Scope=\""+queryView.Scope+"\"";
            }
            var folderUrl = SPContext.Current.RootFolderUrl;
            if(!String.IsNullOrEmpty(folderUrl)){
                var folder = this.Web.GetFolder(folderUrl);
                if (folder.UniqueId != List.RootFolder.UniqueId)
                {
                    spQuery.Folder = folder;
                }
            }

            var result = this.List.GetItems(spQuery).GetDataTable();
            if (result == null || result.Rows.Count==0)
            {
                Page.ClientScript.RegisterStartupScript(this.GetType(),"alert","alert('查询结果为空');", true);
                return;
            }

            for (var i = result.Columns.Count - 1; i >= 0; i--)
            {
                DataColumn col = result.Columns[i];
                SPField f = List.Fields.GetFieldByInternalName(col.ColumnName);
                if (result.Columns.Contains(f.Title))
                {
                    var colWithSameTitle = result.Columns[f.Title];
                    if (colWithSameTitle != col)
                    {
                        result.Columns.Remove(colWithSameTitle); //重复的列           
                    }
                }
                col.ColumnName = f.Title;// +f.AuthoringInfo;                
            }

            //下载文件名限制32字符 16 汉字
            int maxlength = 15;
            string fileName = this.List.Title + ".csv";
            if (fileName.Length > maxlength)
            {
                fileName = "-" + fileName.Substring(fileName.Length - maxlength, maxlength);
            }

            fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8); //必须编码，不然文件名会出现乱码

            var response = this.Page.Response;

            response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
            //response.Charset = "UTF-8";
            response.ContentEncoding = System.Text.Encoding.UTF8;
            //response.ContentType = "application/ms-excel";
            response.ContentType = "application/octet-stream";


            result.ToCSVStream(HttpContext.Current.Response.OutputStream, true);
            response.End();
        }

        void btnSearches_Click(object sender, EventArgs e)
        {
            OnSearchButtonClick(sender, e);
        }

        protected virtual void OnSearchButtonClick(object sender, EventArgs e)
        {
            //restore to first page.

        }

        #endregion 
    }

}
